import os.path as path
import pickle
from datetime import datetime

import matplotlib.pyplot as plt
import numpy as np
import prettytable as pt
from PyQt5 import QtGui

from PyQt5.QtCore import QThread, pyqtSignal, Qt, QPoint
from PyQt5.QtGui import QCloseEvent

from PyQt5.QtWidgets import QMainWindow, QFileDialog, QMenu, QApplication

from Algorithm.ErrorAnalyser import ErrorAnalyser, Error
from ui_error_analyse import Ui_Error_Analyse


class ErrorAnalyserThread(QThread):
    finishSignal = pyqtSignal(ErrorAnalyser)

    def __init__(self, target_file, ref_file, column_index,
                 delimiter='\s+',
                 skip_rows=0,
                 cdf_dense=None,
                 write2file=False,
                 offset=None,
                 error_hz=5):
        super(ErrorAnalyserThread, self).__init__()
        self.target_file = target_file
        self.ref_file = ref_file
        self.column_index = column_index
        self.delimiter = delimiter
        self.skip_rows = skip_rows
        self.cdf_dense = cdf_dense
        self.error_hz = error_hz
        self.write2file = write2file
        self.thread = None
        self.offset = offset

    def run(self) -> None:
        e = ErrorAnalyser(self.target_file, self.ref_file, self.column_index,
                          skip_rows=self.skip_rows,
                          delimiter=self.delimiter,
                          error_hz=self.error_hz,
                          write2file=self.write2file,
                          offset=self.offset,
                          bins=self.cdf_dense)
        e.analyse(True, True)
        self.finishSignal.emit(e)


class ErrorAnalyseWindow(QMainWindow, Ui_Error_Analyse):
    def __init__(self):
        super(ErrorAnalyseWindow, self).__init__()
        self.setupUi(self)
        self.btnBrowseTargetFile.clicked.connect(self.onBtnBrowserTargetFile)
        self.btnBrowseRefFile.clicked.connect(self.onBtnBrowserRefFile)
        self.btnCalculateError.clicked.connect(self.onBtnStart)
        self.btnClosePlot.clicked.connect(self.onBtnClosePlot)
        self.btnClearLog.clicked.connect(self.clear_log)
        self.btnSaveFig.clicked.connect(self.onBtnSaveFig)
        self.option = {}
        self.thread = None
        self.column_index = None
        self.set_gui()
        self.listLog.customContextMenuRequested[QPoint].connect(self.__right_menu_on_log)

        self.outage_index = None
        self.figs = []

        self.title_font = {'family': 'Times New Roman', 'size': 14}
        self.label_font = {'family': 'Times New Roman', 'size': 14}
        self.legend_font = {'family': 'Times New Roman', 'size': 10}
        self.font = 'Times New Roman'
        self.size = 10
        self.dpi = 200
        self.figure_size = [6.4, 4.8]

    def set_gui(self):
        self.option['column_index'] = self.treeWidget.topLevelItem(0)
        self.option['gps_week_index'] = self.treeWidget.topLevelItem(0).child(0)
        self.option['gps_second_index'] = self.treeWidget.topLevelItem(0).child(1)
        self.option['latitude_index'] = self.treeWidget.topLevelItem(0).child(2)
        self.option['longitude_index'] = self.treeWidget.topLevelItem(0).child(3)
        self.option['height_index'] = self.treeWidget.topLevelItem(0).child(4)
        self.option['vn_index'] = self.treeWidget.topLevelItem(0).child(5)
        self.option['ve_index'] = self.treeWidget.topLevelItem(0).child(6)
        self.option['vd_index'] = self.treeWidget.topLevelItem(0).child(7)
        self.option['roll_index'] = self.treeWidget.topLevelItem(0).child(8)
        self.option['pitch_index'] = self.treeWidget.topLevelItem(0).child(9)
        self.option['yaw_index'] = self.treeWidget.topLevelItem(0).child(10)
        self.option['q_index'] = self.treeWidget.topLevelItem(0).child(11)
        self.option['ns_index'] = self.treeWidget.topLevelItem(0).child(12)
        self.option['error_hz'] = self.treeWidget.topLevelItem(1)
        self.option['skip_rows'] = self.treeWidget.topLevelItem(2)
        self.option['cdf_dense'] = self.treeWidget.topLevelItem(3)
        self.option['write2file'] = self.treeWidget.topLevelItem(4)
        self.option['offset_check'] = self.treeWidget.topLevelItem(5)
        self.option['offset'] = [self.treeWidget.topLevelItem(5).child(0),
                                 self.treeWidget.topLevelItem(5).child(1),
                                 self.treeWidget.topLevelItem(5).child(2)]

    def __right_menu_on_log(self, point):
        popMenu = QMenu()
        copy_action = popMenu.addAction(u'Copy')
        copy_action.triggered.connect(lambda: self.__copy_log(point))
        clear_action = popMenu.addAction(u'Clear')
        clear_action.triggered.connect(self.clear_log)
        popMenu.exec_(QtGui.QCursor.pos())

    def __copy_log(self, point):
        item = self.listLog.itemAt(point)
        if not item is None:
            clipboard = QApplication.clipboard()
            clipboard.setText(item.text())
            self.show_log("copy to clip board")

    def onBtnStart(self):
        self.show_log("start error analysing...")
        target_file = self.editTargetFile.text()
        ref_file = self.editRefFile.text()

        if path.isdir(target_file):
            self.show_log("target is not a file:\n%s" % target_file)
            return
        if path.isdir(ref_file):
            self.show_log("ref file is not a file:\n%s" % ref_file)
            return
        try:
            cdf_dense = None
            error_hz = int(self.option['error_hz'].text(1))
            skip_rows = int(self.option['skip_rows'].text(1))
            if self.option['cdf_dense'].checkState(1) == Qt.Checked:
                cdf_dense = int(self.option['cdf_dense'].text(1))
        except Exception as e:
            error_hz = 5
            skip_rows = 0
            cdf_dense = None
            self.show_log(str(e.args))
        try:
            column_index = [
                int(self.option['gps_week_index'].text(1)),
                int(self.option['gps_second_index'].text(1)),
                int(self.option['latitude_index'].text(1)),
                int(self.option['longitude_index'].text(1)),
                int(self.option['height_index'].text(1)),
                int(self.option['vn_index'].text(1)),
                int(self.option['ve_index'].text(1)),
                int(self.option['vd_index'].text(1)),
                int(self.option['roll_index'].text(1)),
                int(self.option['pitch_index'].text(1)),
                int(self.option['yaw_index'].text(1)),
                int(self.option['q_index'].text(1)),
                int(self.option['ns_index'].text(1)),
            ]
            self.column_index = column_index

        except Exception as e:
            self.column_index = [0, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1]
            self.show_log(str(e.args))

        write2file = self.option['write2file'].checkState(1) == Qt.Checked
        offset = None
        if self.option['offset_check'].checkState(1) == Qt.Checked:
            offset = [float(t.text(1)) for t in self.option['offset']]
            print("offset enable")
        self.thread = ErrorAnalyserThread(target_file, ref_file, self.column_index,
                                          skip_rows=skip_rows,
                                          cdf_dense=cdf_dense,
                                          write2file=write2file,
                                          error_hz=error_hz,
                                          offset=offset
                                          )

        self.thread.finishSignal.connect(self.onErrorAnalyseFinished)
        self.thread.start()
        self.btnCalculateError.setEnabled(False)
        self.figs.clear()

    def onBtnClosePlot(self):
        self.show_log('close plot')
        plt.close('all')
        # 加这句是避免被close掉的figure被dump之后是不能打开的
        self.figs.clear()

    def onBtnSaveFig(self):
        self.show_log("Save fig")
        target_path = self.editTargetFile.text()
        target_path_dir = target_path.replace(target_path.split('/')[-1], "pigs")
        savepath, file_type = QFileDialog.getSaveFileName(caption="Save to pig file", directory=target_path_dir,
                                                          filter="PIG files(*.pig);;Images(*.png)")
        if savepath == "": return
        cnt = 0
        if file_type == "Images(*.png)":
            cnt = 0
            for fig in self.figs:
                file_path = savepath + "%s.png" % fig.axes[0].get_title().replace(' ', '-')
                print("save ", file_path)
                fig.savefig(file_path)
                cnt = cnt + 1
        if file_type == "PIG files(*.pig)":
            cnt = 0
            for fig in self.figs:
                file_path = savepath + "%s.pig" % fig.axes[0].get_title().replace(' ', '-')
                print("save ", file_path)
                with open(file_path, 'wb') as f:
                    pickle.dump(fig, f)
                cnt = cnt + 1
        self.show_log("Save %d image(s) to " % cnt + savepath)

    def onErrorAnalyseFinished(self, e: ErrorAnalyser):
        self.btnCalculateError.setEnabled(True)
        self.show_log("error analyse finished")
        if e.exception is not None:
            self.show_log(str(e.exception))
            return
        # self.showRMS(e)
        plt.close('all')
        plt.rcParams['xtick.direction'] = 'in'  # 将x周的刻度线方向设置向内
        plt.rcParams['ytick.direction'] = 'in'  # 将y轴的刻度方向设置向内
        self.__plot_outage_error(e)
        self.__plot_position_error(e)
        self.__plot_vel_error(e)
        self.__plot_atti_error(e)
        self.__plot_tables(e)
        self.__plot_2d_error(e)
        self.__plot_3d_error(e)
        plt.show()

    def __plot_outage_error(self, e: ErrorAnalyser):
        if self.column_index[11] <= 0: return
        keyindex = []
        pre_status = 0
        for i, k in enumerate(e.sensors_by_time):
            if int(k) & 2 == 0:
                pre_status = 1
            else:
                if pre_status == 1:
                    keyindex.append(i - 1)
                pre_status = 0
        self.outage_index = keyindex
        fig = plt.figure("Outage-2D", dpi=self.dpi, figsize=self.figure_size)
        plt.plot(e.times, e.error_2d.error, '-g')
        plt.plot(e.times[keyindex], e.error_2d.error[keyindex], '*r')
        plt.xlabel("GPS time/s", fontdict=self.label_font)
        plt.ylabel("Error/m", fontdict=self.label_font)
        plt.xticks(fontproperties=self.font, size=self.size)
        plt.yticks(fontproperties=self.font, size=self.size)
        plt.grid(True)
        plt.title("Outage Error(2D)", fontdict=self.title_font)
        self.figs.append(fig)
        self.show_log("2D outage RMS:%.5f" % (np.mean(e.error_2d.error[keyindex])))
        fig = plt.figure("Outage 3D", dpi=self.dpi, figsize=self.figure_size)
        plt.plot(e.times, e.error_3d.error, '-g')
        plt.plot(e.times[keyindex], e.error_3d.error[keyindex], '*r')
        plt.xlabel("GPS time/s", fontdict=self.label_font)
        plt.ylabel("Error/m", fontdict=self.label_font)
        plt.xticks(fontproperties=self.font, size=self.size)
        plt.yticks(fontproperties=self.font, size=self.size)
        plt.grid(True)
        plt.title("Outage Error(3D)", fontdict=self.title_font)
        self.show_log("3D outage RMS:%.5f" % (np.mean(e.error_3d.error[keyindex])))
        self.figs.append(fig)
        plt.show()

    def __plot_position_error(self, e: ErrorAnalyser):
        if self.column_index[2] > 0 and self.column_index[3] > 0 and self.column_index[4] > 0:
            ylabels = ["X/m", "Y/m", "Z/m"]
            fig = plt.figure("pos_err", dpi=self.dpi, figsize=self.figure_size)
            plt.subplot(3, 1, 1)
            plt.ylabel(ylabels[0], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.title("Position Error", fontdict=self.title_font)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[2]].error, 'g')
            if self.column_index[11] > 0:
                plt.plot(e.times[self.outage_index] - e.times[0], e.errs[self.column_index[2]].error[self.outage_index],
                         '*r')
            plt.subplot(3, 1, 2)
            plt.ylabel(ylabels[1], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[3]].error, 'g')
            if self.column_index[11] > 0:
                plt.plot(e.times[self.outage_index] - e.times[0], e.errs[self.column_index[3]].error[self.outage_index],
                         '*r')
            plt.subplot(3, 1, 3)
            plt.ylabel(ylabels[2], fontdict=self.label_font)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[4]].error, 'g')
            if self.column_index[11] > 0:
                plt.plot(e.times[self.outage_index] - e.times[0], e.errs[self.column_index[4]].error[self.outage_index],
                         '*r')
            plt.xlabel("GPS time/s - %.0f" % e.times[0], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            self.figs.append(fig)
            ''' plot cdf and pdf'''
            fig = plt.figure('PDF and CDF of Position Error', dpi=self.dpi, figsize=self.figure_size)
            plt.title("PDF and CDF of Position Error", fontdict=self.title_font)
            _1st = 0.6826
            _2st = 0.9544
            ylabels = ["X", "Y", "Z"]
            for k in [0, 1, 2]:
                plt.subplot(3, 1, k + 1)
                if k == 0:
                    plt.title("PDF and CDF of Position Error", fontdict=self.title_font)
                plt.ylabel(ylabel=ylabels[k], fontdict=self.label_font)
                idx = self.column_index[2 + k]
                err = e.errs[idx]
                self.__plot_cdf_pdf(err)
            plt.xlabel("Error/m", fontdict=self.label_font)
            self.figs.append(fig)

    def __plot_vel_error(self, e: ErrorAnalyser):
        if self.column_index[5] > 0 and self.column_index[6] > 0 and self.column_index[7] > 0:
            ylabels = ["X/(m/s)", "Y/(m/s)", "Z/(m/s)"]
            fig = plt.figure("Velocity Error", dpi=self.dpi, figsize=self.figure_size)
            plt.subplot(3, 1, 1)
            plt.title("Velocity Error", fontdict=self.title_font)
            plt.ylabel(ylabels[0], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[5]].error, 'g')
            plt.subplot(3, 1, 2)
            plt.ylabel(ylabels[1], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[6]].error, 'g')
            plt.subplot(3, 1, 3)
            plt.ylabel(ylabels[2], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[7]].error, 'g')
            plt.grid(True)
            plt.xlabel("GPS time/s - %f" % e.times[0], fontdict=self.label_font)
            self.figs.append(fig)
            ''' plot cdf and pdf'''
            fig = plt.figure('vel_pdf_cdf', dpi=self.dpi, figsize=self.figure_size)
            _1st = 0.6826
            _2st = 0.9544
            ylabels = ["X", "Y", "Z"]
            for k in [0, 1, 2]:
                plt.subplot(3, 1, k + 1)
                if k == 0:
                    plt.title("PDF and CDF of Velocity Error", fontdict=self.title_font)
                plt.ylabel(ylabels[k], fontdict=self.label_font)
                idx = self.column_index[5 + k]
                err = e.errs[idx]
                self.__plot_cdf_pdf(err)
            plt.xlabel("Error/(m/s)", fontdict=self.label_font)
            self.figs.append(fig)

    def __plot_atti_error(self, e: ErrorAnalyser):
        if self.column_index[8] > 0 and self.column_index[9] > 0 and self.column_index[10] > 0:
            ylabels = [r"roll/$\degree$", r"pitch/$\degree$", "yaw/$\degree$"]
            fig = plt.figure("Attitude Error", dpi=self.dpi, figsize=self.figure_size)
            plt.subplot(3, 1, 1)
            plt.title("Attitude Error", fontdict=self.title_font)
            plt.ylabel(ylabels[0], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[8]].error, 'g')
            plt.subplot(3, 1, 2)
            plt.ylabel(ylabels[1], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[9]].error, 'g')
            plt.subplot(3, 1, 3)
            plt.ylabel(ylabels[2], fontdict=self.label_font)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.plot(e.times - e.times[0], e.errs[self.column_index[10]].error, 'g')
            plt.xlabel("GPS time/s - %.0f" % e.times[0], fontdict=self.label_font)
            self.figs.append(fig)
            ''' plot cdf and pdf'''
            fig = plt.figure('atti_pdf_cdf', dpi=self.dpi, figsize=self.figure_size)
            ylabels = ["roll", "pitch", "yaw"]
            for k in [0, 1, 2]:
                plt.subplot(3, 1, k + 1)
                if k == 0:
                    plt.title("PDF and CDF of Attitude Error", fontdict=self.title_font)
                plt.ylabel(ylabels[k], fontdict=self.label_font)
                idx = self.column_index[8 + k]
                err = e.errs[idx]
                self.__plot_cdf_pdf(err)
            plt.xlabel(r"Error/$\degree$", fontdict=self.label_font)
            self.figs.append(fig)

    def __plot_tables(self, e: ErrorAnalyser):
        # Markdown:
        table = pt.PrettyTable()
        table.field_names = [" ", "x error /m", "y error/m", "z error/m"]
        table.border = True
        table.junction_char = "|"
        table.horizontal_char = '-'
        table.vertical_char = '|'
        fmt = "%.4f"

        header2 = ["position error(m)", "velocity error(m/s)", "attitude error(deg)"]
        for k in range(3):
            indexs = self.column_index[3 * k + 2:3 * k + 5]
            if indexs[0] > 0 and indexs[2] > 0 and indexs[1] > 0:
                table.add_row([header2[k] + " 1-$\\sigma$", fmt % e.errs[indexs[0]].first_sigma,
                               fmt % e.errs[indexs[1]].first_sigma, fmt % e.errs[indexs[2]].first_sigma])
                table.add_row(
                    [header2[k] + " 2-$\\sigma$", fmt % e.errs[indexs[0]].second_sigma,
                     fmt % e.errs[indexs[1]].second_sigma,
                     fmt % e.errs[indexs[2]].second_sigma])

                table.add_row([header2[k] + " rms", fmt % e.errs[indexs[0]].rms, fmt % e.errs[indexs[1]].rms,
                               fmt % e.errs[indexs[2]].rms])
        table.add_row(["2D error" + " 1-$\\sigma$", fmt % e.error_2d.first_sigma, "", ""])
        table.add_row(["2D error" + " 2-$\\sigma$", fmt % e.error_2d.second_sigma, "", ""])
        table.add_row(["2D error" + " RMS$", fmt % e.error_2d.rms, "", ""])
        table.add_row(["3D error" + " 1-$\\sigma$", fmt % e.error_3d.first_sigma, "", ""])
        table.add_row(["3D error" + " 2-$\\sigma$", fmt % e.error_3d.second_sigma, "", ""])
        table.add_row(["3D error" + " RMS $\\sigma$", fmt % e.error_3d.rms, "", ""])
        if self.column_index[11] > 0 and self.outage_index is not None:
            table.add_row(["Outage 2D", fmt % (np.mean(e.error_2d.error[self.outage_index])), "", ""])
            table.add_row(["Outage 3D", fmt % (np.mean(e.error_3d.error[self.outage_index])), "", ""])
            table.add_row(
                ["Outage Pos", fmt % (np.sqrt(np.mean(e.errs[self.column_index[2]].error[self.outage_index] ** 2))),
                 fmt % (np.sqrt(np.mean(e.errs[self.column_index[3]].error[self.outage_index] ** 2))),
                 fmt % (np.sqrt(np.mean(e.errs[self.column_index[4]].error[self.outage_index] ** 2))),
                 ])
            if self.column_index[8] > 0 and self.column_index[9] > 0 and self.column_index[10] > 0:
                table.add_row(
                    ["Outage Atti", fmt % (np.sqrt(np.mean(e.errs[self.column_index[8]].error[self.outage_index] ** 2))),
                     fmt % (np.sqrt(np.mean(e.errs[self.column_index[9]].error[self.outage_index] ** 2))),
                     fmt % (np.sqrt(np.mean(e.errs[self.column_index[10]].error[self.outage_index] ** 2))),
                     ])
        print(table)
        self.show_log("\n" + str(table))

    def __plot_cdf_pdf(self, err: Error):
        _1st = 0.6826
        _2st = 0.9544
        hist = err.pdf
        plt.yticks([0, _1st, _2st], fontproperties=self.font, size=self.size)
        plt.xticks(fontproperties=self.font, size=self.size)
        plt.plot(err.edges[1:], hist / max(hist), '-.g')
        plt.plot(err.edges[1:], err.cdf / err.cdf[-1], 'b')
        plt.plot([err.first_sigma, err.first_sigma], [0, _1st], color='#FF6640', ls=':', linewidth=1, marker="None")
        plt.plot([err.edges[1], err.first_sigma], [_1st, _1st], color='#FF6640', ls=':', linewidth=1, marker="None")
        plt.plot([err.second_sigma, err.second_sigma], [0, _2st], color='#FF6640', ls=':', linewidth=1, marker="None")
        plt.plot([err.edges[1], err.second_sigma], [_2st, _2st], color='#FF6640', ls=':', linewidth=1, marker="None")
        plt.annotate(r'$1\sigma=%.4f$' % err.first_sigma,
                     xy=(err.first_sigma, _1st), xytext=(-1, -14),
                     textcoords='offset points', size=14)
        plt.annotate(r'$2\sigma=%.4f$' % err.second_sigma,
                     xy=(err.second_sigma, _2st), xytext=(-1, -14),
                     textcoords='offset points', size=14)
        plt.legend(['PDF', 'CDF'], loc='center right', prop=self.legend_font)

    def __plot_2d_error(self, e: ErrorAnalyser):
        if self.column_index[2] > 0 and self.column_index[3] > 0 and self.column_index[4] > 0:
            fig = plt.figure("error_2d", dpi=self.dpi, figsize=self.figure_size)
            plt.plot(e.times, e.error_2d.error)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.grid(True)
            plt.xlabel("GPS time/s", fontdict=self.label_font)
            plt.ylabel("2D error /m", fontdict=self.label_font)
            plt.title("2D Error", fontdict=self.title_font)
            self.figs.append(fig)
            fig = plt.figure("2D error cdf/pdf", dpi=self.dpi, figsize=self.figure_size)
            plt.title("CDF and PDF of 2D Error", fontdict=self.title_font)
            self.__plot_cdf_pdf(e.error_2d)
            plt.xlabel("Error/m", fontdict=self.label_font)
            self.figs.append(fig)

    def __plot_3d_error(self, e: ErrorAnalyser):
        if self.column_index[2] > 0 and self.column_index[3] > 0 and self.column_index[4] > 0:
            fig = plt.figure("error_3d", dpi=self.dpi, figsize=self.figure_size)
            plt.plot(e.times, e.error_3d.error)
            plt.yticks(fontproperties=self.font, size=self.size)
            plt.xticks(fontproperties=self.font, size=self.size)
            plt.xlabel("GPS time/s", fontdict=self.label_font)
            plt.ylabel("3D Error /m", fontdict=self.label_font)
            plt.grid(True)
            plt.title("3D Error", fontdict=self.title_font)
            self.figs.append(fig)
            fig = plt.figure("CDF and PDF of 3D Error", dpi=self.dpi, figsize=self.figure_size)
            plt.title("CDF and PDF of 3D Error", fontdict=self.title_font)
            self.__plot_cdf_pdf(e.error_3d)
            plt.xlabel("Error /m", fontdict=self.label_font)
            self.figs.append(fig)

    def onBtnBrowserTargetFile(self):
        filepath, suffix = QFileDialog.getOpenFileName()
        self.editTargetFile.setText(filepath)
        self.show_log("目标文件: %s" % filepath)

    def onBtnBrowserRefFile(self):
        filfilepath, suffix = QFileDialog.getOpenFileName()
        self.editRefFile.setText(filfilepath)
        self.show_log("参考文件: %s" % filfilepath)

    def show_log(self, msg):
        stamp = datetime.now().strftime('%H:%M:%S : ')
        item = stamp + msg
        self.listLog.addItem(item)

    def clear_log(self):
        self.listLog.clear()

    def closeEvent(self, a0: QCloseEvent) -> None:
        plt.close('all')  # 关闭绘图


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    errorAnalyseWindow = ErrorAnalyseWindow()
    errorAnalyseWindow.show()
    sys.exit(app.exec_())
